#include "xdecode.h"
#include "xcodec.h"
#include <mutex>
extern "C" {
#include "libavutil/frame.h"
#include "libavutil/hwcontext.h"
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/log.h>
#include <libavutil/opt.h>
}
using namespace std;
// 发送解码
bool XDecode::Send(const AVPacket *pkt) {
  std::unique_lock<std::mutex> lock(mux_);
  if (!c_)
    return false;
  int ret = avcodec_send_packet(c_, pkt);
  return ret == 0;
}
bool XDecode::Receive(AVFrame *frame) {
  std::unique_lock<std::mutex> lock(mux_);
  if (!c_)
    return false;
  auto f = frame;
  if (c_->hw_frames_ctx) {
    f = av_frame_alloc(); // 硬解码转换用
  }
  int re = avcodec_receive_frame(c_, f);
  if (re == 0) {
    if (c_->hw_frames_ctx) {
      // 从显存赋值到内存
      re = av_hwframe_transfer_data(frame, f, 0);
      av_frame_free(&f);
      if (re != 0) {
        PrintErr(re);
        return false;
      }
    }
    return true;
  }
  if (c_->hw_frames_ctx)
    av_frame_free(&f);
  return false;
}
// bool XDecode::Receive(std::vector<AVFrame *> &frameList) {
//   std::unique_lock<std::mutex> lock(mux_);
//   if (!c_)
//     return false;
//   AVFrame *frame = CreateFrame();
//   int ret = avcodec_receive_frame(c_, frame);
//   if (ret == 0)
//     return true;
//   return false;
// }
std::vector<AVFrame *> XDecode::End() {
  /// 取出缓存数据
  std::vector<AVFrame *> res;
  std::unique_lock<std::mutex> lock(mux_);
  if (!c_)
    return res;
  int re = avcodec_send_packet(c_, NULL);
  if (re != 0) {
    PrintErr(re);
    return res;
  }
  while (re >= 0) {
    auto frame = av_frame_alloc();
    auto f = frame;
    if (c_->hw_frames_ctx) {
      f = av_frame_alloc(); // 硬解码转换用
    }
    re = avcodec_receive_frame(c_, f);
    if (re != 0) {
      PrintErr(re);
      av_frame_free(&frame);
      if (c_->hw_frames_ctx) {
        av_frame_free(&f);
      }
      break;
    }
    if (c_->hw_frames_ctx) {
      // 从显存赋值到内存
      re = av_hwframe_transfer_data(frame, f, 0);
      av_frame_free(&f);
      if (re != 0) {
        PrintErr(re);
        break;
      }
    }
    res.push_back(frame);
  }
  return res;
}

bool XDecode::InitHW(int hw_type) {
  std::unique_lock<std::mutex> lock(mux_);
  if (!c_)
    return false;
  // 硬件加速上下文
  AVBufferRef *ctx = nullptr;
  AVHWDeviceType hwType = AVHWDeviceType(hw_type);
  auto re = av_hwdevice_ctx_create(&ctx, hwType, NULL, NULL, 0);
  if (re != 0) {
    PrintErr(re);
    return false;
  }
  c_->hw_device_ctx = ctx;
  const char *buf = av_hwdevice_get_type_name(hwType);
  av_log(nullptr, AV_LOG_DEBUG, "硬件%s加速初始化成功", buf);
  return true;
}
